using DaoHang.Data;
using DaoHang.Models;
using Microsoft.EntityFrameworkCore;
using System.Collections.Concurrent;

namespace DaoHang.Services
{
    /// <summary>
    /// 轻量级日志服务实现
    /// 支持控制台和SQLite数据库双重输出，多线程安全
    /// </summary>
    public class LightLogService : ILogService
    {
        private readonly IServiceScopeFactory serviceScopeFactory;
        private readonly IHttpContextAccessor httpContextAccessor;
        private readonly ConcurrentQueue<SystemLog> logQueue;
        private readonly Timer flushTimer;
        private readonly object lockObject = new object();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serviceScopeFactory">服务作用域工厂</param>
        /// <param name="httpContextAccessor">HTTP上下文访问器</param>
        public LightLogService(IServiceScopeFactory serviceScopeFactory, IHttpContextAccessor httpContextAccessor)
        {
            this.serviceScopeFactory = serviceScopeFactory;
            this.httpContextAccessor = httpContextAccessor;
            this.logQueue = new ConcurrentQueue<SystemLog>();

            // 创建定时器，每5秒批量写入数据库
            this.flushTimer = new Timer(FlushLogsToDatabase, null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
        }

        /// <summary>
        /// 记录信息日志
        /// </summary>
        public async Task LogInformationAsync(string message, string category = "System", string? userId = null, string? additionalData = null)
        {
            await LogAsync("Information", message, category, userId, additionalData);
        }

        /// <summary>
        /// 记录警告日志
        /// </summary>
        public async Task LogWarningAsync(string message, string category = "System", string? userId = null, string? additionalData = null)
        {
            await LogAsync("Warning", message, category, userId, additionalData);
        }

        /// <summary>
        /// 记录错误日志
        /// </summary>
        public async Task LogErrorAsync(string message, Exception? exception = null, string category = "System", string? userId = null, string? additionalData = null)
        {
            var exceptionInfo = exception != null ? $"{exception.Message}\n{exception.StackTrace}" : null;
            await LogAsync("Error", message, category, userId, additionalData, exceptionInfo);
        }

        /// <summary>
        /// 记录调试日志
        /// </summary>
        public async Task LogDebugAsync(string message, string category = "System", string? userId = null, string? additionalData = null)
        {
            await LogAsync("Debug", message, category, userId, additionalData);
        }

        /// <summary>
        /// 记录跟踪日志
        /// </summary>
        public async Task LogTraceAsync(string message, string category = "System", string? userId = null, string? additionalData = null)
        {
            await LogAsync("Trace", message, category, userId, additionalData);
        }

        /// <summary>
        /// 核心日志记录方法
        /// </summary>
        private async Task LogAsync(string level, string message, string category, string? userId, string? additionalData, string? exception = null)
        {
            try
            {
                // 获取HTTP上下文信息
                var httpContext = httpContextAccessor.HttpContext;
                var ipAddress = httpContext?.Connection?.RemoteIpAddress?.ToString();
                var userAgent = httpContext?.Request?.Headers["User-Agent"].ToString();
                var requestPath = httpContext?.Request?.Path.ToString();

                // 创建日志对象
                var logEntry = new SystemLog
                {
                    Level = level,
                    Category = category,
                    Message = message,
                    Exception = exception,
                    UserId = userId,
                    IpAddress = ipAddress,
                    UserAgent = userAgent,
                    RequestPath = requestPath,
                    AdditionalData = additionalData,
                    CreateTime = DateTime.Now
                };

                // 输出到控制台（带颜色）
                WriteToConsole(logEntry);

                // 加入队列等待批量写入数据库
                logQueue.Enqueue(logEntry);
            }
            catch (Exception ex)
            {
                // 日志记录失败时输出到控制台
                Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [ERROR] [LogService] 日志记录失败: {ex.Message}");
            }

            await Task.CompletedTask;
        }

        /// <summary>
        /// 输出日志到控制台
        /// </summary>
        private void WriteToConsole(SystemLog logEntry)
        {
            try
            {
                lock (lockObject)
                {
                    // 根据日志级别设置颜色
                    var originalColor = Console.ForegroundColor;
                    switch (logEntry.Level.ToUpper())
                    {
                        case "ERROR":
                            Console.ForegroundColor = ConsoleColor.Red;
                            break;
                        case "WARNING":
                            Console.ForegroundColor = ConsoleColor.Yellow;
                            break;
                        case "INFORMATION":
                            Console.ForegroundColor = ConsoleColor.Green;
                            break;
                        case "DEBUG":
                            Console.ForegroundColor = ConsoleColor.Cyan;
                            break;
                        case "TRACE":
                            Console.ForegroundColor = ConsoleColor.Gray;
                            break;
                        default:
                            Console.ForegroundColor = ConsoleColor.White;
                            break;
                    }

                    // 输出格式化的日志
                    var timestamp = logEntry.CreateTime.ToString("yyyy-MM-dd HH:mm:ss");
                    var levelPadded = logEntry.Level.ToUpper().PadRight(11);
                    var categoryPadded = logEntry.Category.PadRight(10);
                    
                    Console.WriteLine($"[{timestamp}] [{levelPadded}] [{categoryPadded}] {logEntry.Message}");

                    // 如果有异常信息，也输出
                    if (!string.IsNullOrEmpty(logEntry.Exception))
                    {
                        Console.WriteLine($"{"".PadRight(34)} Exception: {logEntry.Exception}");
                    }

                    // 恢复原始颜色
                    Console.ForegroundColor = originalColor;
                }
            }
            catch
            {
                // 忽略控制台输出错误
            }
        }

        /// <summary>
        /// 定时批量写入数据库
        /// </summary>
        private async void FlushLogsToDatabase(object? state)
        {
            if (logQueue.IsEmpty) return;

            var logsToWrite = new List<SystemLog>();
            
            // 从队列中取出所有待写入的日志
            while (logQueue.TryDequeue(out var logEntry))
            {
                logsToWrite.Add(logEntry);
            }

            if (logsToWrite.Count == 0) return;

            try
            {
                using var scope = serviceScopeFactory.CreateScope();
                var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
                
                // 批量添加到数据库
                await context.SystemLogs.AddRangeAsync(logsToWrite);
                await context.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                // 数据库写入失败时，重新加入队列（避免丢失日志）
                foreach (var log in logsToWrite)
                {
                    logQueue.Enqueue(log);
                }
                
                Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [ERROR] [LogService] 数据库写入失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 分页获取日志
        /// </summary>
        public async Task<(List<SystemLog> logs, int totalCount)> GetLogsAsync(int pageIndex = 1, int pageSize = 50)
        {
            // 在查询前确保队列中的日志已写入数据库
            await ForceFlushLogsToDatabase();
            
            using var scope = serviceScopeFactory.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

            var query = context.SystemLogs.OrderByDescending(l => l.CreateTime);
            var totalCount = await query.CountAsync();
            var logs = await query.Skip((pageIndex - 1) * pageSize)
                                 .Take(pageSize)
                                 .ToListAsync();

            return (logs, totalCount);
        }

        /// <summary>
        /// 按级别获取日志
        /// </summary>
        public async Task<(List<SystemLog> logs, int totalCount)> GetLogsByLevelAsync(string level, int pageIndex = 1, int pageSize = 50)
        {
            // 在查询前确保队列中的日志已写入数据库
            await ForceFlushLogsToDatabase();
            
            using var scope = serviceScopeFactory.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

            var query = context.SystemLogs.Where(l => l.Level == level)
                                         .OrderByDescending(l => l.CreateTime);

            var totalCount = await query.CountAsync();
            var logs = await query.Skip((pageIndex - 1) * pageSize)
                                 .Take(pageSize)
                                 .ToListAsync();

            return (logs, totalCount);
        }

        /// <summary>
        /// 按时间范围获取日志
        /// </summary>
        public async Task<(List<SystemLog> logs, int totalCount)> GetLogsByTimeRangeAsync(DateTime startTime, DateTime endTime, int pageIndex = 1, int pageSize = 50)
        {
            // 在查询前确保队列中的日志已写入数据库
            await ForceFlushLogsToDatabase();
            
            using var scope = serviceScopeFactory.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

            var query = context.SystemLogs.Where(l => l.CreateTime >= startTime && l.CreateTime <= endTime)
                                         .OrderByDescending(l => l.CreateTime);

            var totalCount = await query.CountAsync();
            var logs = await query.Skip((pageIndex - 1) * pageSize)
                                 .Take(pageSize)
                                 .ToListAsync();

            return (logs, totalCount);
        }

        /// <summary>
        /// 搜索日志
        /// </summary>
        public async Task<(List<SystemLog> logs, int totalCount)> SearchLogsAsync(string keyword, string? level = null, int pageIndex = 1, int pageSize = 50)
        {
            // 在查询前确保队列中的日志已写入数据库
            await ForceFlushLogsToDatabase();
            
            using var scope = serviceScopeFactory.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

            var query = context.SystemLogs.AsQueryable();

            // 关键字搜索
            if (!string.IsNullOrEmpty(keyword))
            {
                query = query.Where(l => l.Message.Contains(keyword) || 
                                        l.Category.Contains(keyword) ||
                                        (l.Exception != null && l.Exception.Contains(keyword)));
            }

            // 级别过滤
            if (!string.IsNullOrEmpty(level))
            {
                query = query.Where(l => l.Level == level);
            }

            query = query.OrderByDescending(l => l.CreateTime);

            var totalCount = await query.CountAsync();
            var logs = await query.Skip((pageIndex - 1) * pageSize)
                                 .Take(pageSize)
                                 .ToListAsync();

            return (logs, totalCount);
        }

        /// <summary>
        /// 获取日志统计信息
        /// </summary>
        public async Task<Dictionary<string, int>> GetLogStatisticsAsync()
        {
            // 在查询前确保队列中的日志已写入数据库
            await ForceFlushLogsToDatabase();
            
            using var scope = serviceScopeFactory.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

            var stats = await context.SystemLogs.GroupBy(l => l.Level)
                                                .Select(g => new { Level = g.Key, Count = g.Count() })
                                                .ToDictionaryAsync(x => x.Level, x => x.Count);

            return stats;
        }

        /// <summary>
        /// 获取所有日志
        /// </summary>
        public async Task<List<SystemLog>> GetAllAsync()
        {
            // 在查询前确保队列中的日志已写入数据库
            await ForceFlushLogsToDatabase();
            
            using var scope = serviceScopeFactory.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

            return await context.SystemLogs.OrderByDescending(l => l.CreateTime).ToListAsync();
        }

        /// <summary>
        /// 清理旧日志
        /// </summary>
        public async Task<int> CleanupOldLogsAsync(int daysToKeep = 30)
        {
            // 在操作前确保队列中的日志已写入数据库
            await ForceFlushLogsToDatabase();
            
            using var scope = serviceScopeFactory.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

            var cutoffDate = DateTime.Now.AddDays(-daysToKeep);
            var oldLogs = await context.SystemLogs.Where(l => l.CreateTime < cutoffDate).ToListAsync();

            if (oldLogs.Count > 0)
            {
                context.SystemLogs.RemoveRange(oldLogs);
                await context.SaveChangesAsync();
            }

            return oldLogs.Count;
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            flushTimer?.Dispose();
            
            // 在释放前最后一次刷新日志到数据库
            // 同步调用，确保完成刷新
            try
            {
                ForceFlushLogsToDatabase().GetAwaiter().GetResult();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [ERROR] [LogService] 服务释放时刷新日志失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取所有日志分类
        /// </summary>
        /// <returns>日志分类列表</returns>
        public async Task<List<string>> GetLogCategoriesAsync()
        {
            // 在查询前确保队列中的日志已写入数据库
            await ForceFlushLogsToDatabase();
            
            using var scope = serviceScopeFactory.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            
            return await context.SystemLogs
                .Select(l => l.Category)
                .Distinct()
                .OrderBy(c => c)
                .ToListAsync();
        }

        /// <summary>
        /// 获取日志（带过滤和分页）
        /// </summary>
        /// <param name="level">日志级别</param>
        /// <param name="category">日志分类</param>
        /// <param name="searchText">搜索文本</param>
        /// <param name="page">页码</param>
        /// <param name="pageSize">每页数量</param>
        /// <returns>日志列表和总数</returns>
        public async Task<(List<LogEntry> Logs, int TotalCount)> GetLogsAsync(string? level = null, string? category = null, string? searchText = null, int page = 1, int pageSize = 20)
        {
            // 在查询前确保队列中的日志已写入数据库
            await ForceFlushLogsToDatabase();
            
            using var scope = serviceScopeFactory.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            
            // 构建查询
            var query = context.SystemLogs.AsQueryable();
            
            // 应用过滤条件
            if (!string.IsNullOrEmpty(level))
            {
                query = query.Where(l => l.Level == level);
            }
            
            if (!string.IsNullOrEmpty(category))
            {
                query = query.Where(l => l.Category == category);
            }
            
            if (!string.IsNullOrEmpty(searchText))
            {
                query = query.Where(l => l.Message.Contains(searchText) || 
                                        (l.Exception != null && l.Exception.Contains(searchText)) ||
                                        (l.AdditionalData != null && l.AdditionalData.Contains(searchText)));
            }
            
            // 获取总记录数
            var totalCount = await query.CountAsync();
            
            // 分页并排序
            var logs = await query
                .OrderByDescending(l => l.CreateTime)
                .Skip((page - 1) * pageSize)
                .Take(pageSize)
                .ToListAsync();
                
            // 将SystemLog转换为LogEntry
            var logEntries = logs.Select(l => new LogEntry
            {
                Id = l.Id,
                Level = l.Level,
                Category = l.Category,
                Message = l.Message,
                Exception = l.Exception,
                Timestamp = l.CreateTime,
                IpAddress = l.IpAddress,
                Username = l.UserId,
                Properties = l.AdditionalData
            }).ToList();
            
            return (logEntries, totalCount);
        }

        /// <summary>
        /// 清空所有日志
        /// </summary>
        /// <returns>清空的日志数量</returns>
        public async Task<int> ClearLogsAsync()
        {
            // 在操作前确保队列中的日志已写入数据库
            await ForceFlushLogsToDatabase();
            
            using var scope = serviceScopeFactory.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            
            // 获取当前日志数量
            var count = await context.SystemLogs.CountAsync();
            
            // 清空日志表
            await context.Database.ExecuteSqlRawAsync("DELETE FROM SystemLogs");
            
            return count;
        }
        
        /// <summary>
        /// 强制将队列中的所有日志立即写入数据库
        /// </summary>
        private async Task ForceFlushLogsToDatabase()
        {
            if (logQueue.IsEmpty) return;

            var logsToWrite = new List<SystemLog>();
            
            // 从队列中取出所有待写入的日志
            while (logQueue.TryDequeue(out var logEntry))
            {
                logsToWrite.Add(logEntry);
            }

            if (logsToWrite.Count == 0) return;

            try
            {
                using var scope = serviceScopeFactory.CreateScope();
                var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
                
                // 批量添加到数据库
                await context.SystemLogs.AddRangeAsync(logsToWrite);
                await context.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                // 数据库写入失败时，重新加入队列（避免丢失日志）
                foreach (var log in logsToWrite)
                {
                    logQueue.Enqueue(log);
                }
                
                Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [ERROR] [LogService] 数据库写入失败: {ex.Message}");
            }
        }
    }
} 